package com.atguigu.lease.common.utils;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;

public class JwtUtil {
    // 设置token过期时间，单位为毫秒，默认为1小时
    private static long tokenExpiration = 60 * 60 * 1000L;
    // 设置用于签名token的密钥，使用固定的字符串生成HMAC SHA密钥
    private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());

    /**
     * 创建JWT token
     * @param userId 用户ID
     * @param username 用户名
     * @return 生成的token字符串
     */
    public static String createToken(Long userId, String username) {
        String token = Jwts.builder().
                // 设置主题信息
                setSubject("USER_INFO").
                // 设置过期时间，当前时间加上配置的过期时长
                setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)).
                // 添加自定义声明，存储用户ID
                claim("userId", userId).
                // 添加自定义声明，存储用户名
                claim("username", username).
                // 使用指定的密钥进行签名
                signWith(tokenSignKey).
                // 使用GZIP压缩token
                compressWith(CompressionCodecs.GZIP).
                // 构建成紧凑的URL安全字符串
                compact();
        return token;
    }

    /**
     * 解析JWT token
     * @param token 待解析的token字符串
     * @return 解析出的Claims对象，包含token中的所有声明信息
     * @throws LeaseException TOKEN_EXPIRED: token已过期, TOKEN_INVALID: token无效
     */
    public static Claims parseToken(String token) {
        try {
            // 使用JWT解析器构建器设置签名密钥并构建解析器
            Jws<Claims> claimsJws = Jwts.parserBuilder().
                    setSigningKey(tokenSignKey).
                    build().parseClaimsJws(token);
            // 返回解析后的声明信息
            return claimsJws.getBody();

        } catch (ExpiredJwtException e) {
            // 捕获token过期异常，抛出自定义的租赁异常，错误码为TOKEN_EXPIRED
            throw new LeaseException(ResultCodeEnum.TOKEN_EXPIRED);
        } catch (JwtException e) {
            // 捕获其他JWT相关异常，抛出自定义的租赁异常，错误码为TOKEN_INVALID
            throw new LeaseException(ResultCodeEnum.TOKEN_INVALID);
        }
    }
}
